interface IndexConfig {
    name: string;
    keyPath?: string;
    unique?: boolean;
  }
  
  export class IndexedDBHelper<T extends { [key: string]: any }> {
    private dbName: string;
    private version: number;
    private db: IDBDatabase | null = null;
  
    constructor(dbName: string, version: number = 1) {
      this.dbName = dbName;
      this.version = version;
    }
  
    open(storeName: string, keyPath: string = 'id', indexes: IndexConfig[] = []): Promise<IDBDatabase> {
      return new Promise((resolve, reject) => {
        const request = indexedDB.open(this.dbName, this.version);
  
        request.onupgradeneeded = (event: IDBVersionChangeEvent) => {
          const db = (event.target as IDBOpenDBRequest).result;
  
          if (!db.objectStoreNames.contains(storeName)) {
            const store = db.createObjectStore(storeName, { keyPath });
  
            indexes.forEach(index => {
              store.createIndex(index.name, index.keyPath ?? index.name, { unique: !!index.unique });
            });
          }
        };
  
        request.onsuccess = (event: Event) => {
          this.db = (event.target as IDBOpenDBRequest).result;
          resolve(this.db);
        };
  
        request.onerror = () => reject(request.error);
      });
    }
  
    private getStore(storeName: string, mode: IDBTransactionMode = 'readonly'): IDBObjectStore {
      if (!this.db) throw new Error("Database not opened.");
      const tx = this.db.transaction(storeName, mode);
      return tx.objectStore(storeName);
    }
  
    add(storeName: string, data: T): Promise<IDBValidKey> {
      return new Promise((resolve, reject) => {
        const store = this.getStore(storeName, 'readwrite');
        const request = store.add(data);
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
      });
    }
  
    get(storeName: string, key: IDBValidKey): Promise<T | undefined> {
      return new Promise((resolve, reject) => {
        const store = this.getStore(storeName);
        const request = store.get(key);
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
      });
    }
  
    getAll(storeName: string): Promise<T[]> {
      return new Promise((resolve, reject) => {
        const store = this.getStore(storeName);
        const request = store.getAll();
        request.onsuccess = () => resolve(request.result as T[]);
        request.onerror = () => reject(request.error);
      });
    }
  
    update(storeName: string, data: T): Promise<IDBValidKey> {
      return new Promise((resolve, reject) => {
        const store = this.getStore(storeName, 'readwrite');
        const request = store.put(data);
        request.onsuccess = () => resolve(request.result);
        request.onerror = () => reject(request.error);
      });
    }
  
    delete(storeName: string, key: IDBValidKey): Promise<void> {
      return new Promise((resolve, reject) => {
        const store = this.getStore(storeName, 'readwrite');
        const request = store.delete(key);
        request.onsuccess = () => resolve();
        request.onerror = () => reject(request.error);
      });
    }
  
    close(): void {
      if (this.db) {
        this.db.close();
      }
    }
  }
  